import React from 'react';
import { Modal, Tabs, Table, Input, Space, message } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import ProCard from '@ant-design/pro-card';
import SecondPane from './SecondPane';
import MinutePane from './MinutePane';
import HourPane from './HourPane';
import DayPane from './DayPane';
import WeekPane from './WeekPane';
import MonthPane from './MonthPane';
import YearPane from './YearPane';
import { cronExpressionChange } from './utils';

export type ACrontabProps = {
  modalOpen: boolean;
  cronExpression?: string;
  onHandlerOK?: Function;
  onHandlerCancel?: Function;
};

export interface ACrontabState {
  second: string;
  minute: string;
  hour: string;
  day: string;
  month: string;
  week: string;
  year: string;
}

export interface CrontabItem {
  second: string;
  minute: string;
  hour: string;
  day: string;
  month: string;
  week: string;
  year: string;
}

/**
 * 基于react-cron-antd
 * cron时间表达式生成器
 * 属性如下：
 */
class ACrontab extends React.PureComponent<ACrontabProps, ACrontabState> {

  state: ACrontabState = {
    second: '*',
    minute: '*',
    hour: '*',
    day: '*',
    month: '*',
    week: '?',
    year: ''
  }

  cronColumns: ColumnsType<CrontabItem> = [
    {
      title: '秒',
      dataIndex: 'second',
      key: 'second',
      align: 'center',
      ellipsis: true,
    },
    {
      title: '分',
      dataIndex: 'minute',
      key: 'minute',
      align: 'center',
      ellipsis: true,
    },
    {
      title: '时',
      dataIndex: 'hour',
      key: 'hour',
      align: 'center',
      ellipsis: true,
    },
    {
      title: '日',
      dataIndex: 'day',
      key: 'day',
      align: 'center',
      ellipsis: true,
    },
    {
      title: '月',
      dataIndex: 'month',
      key: 'month',
      align: 'center',
      ellipsis: true,
    },
    {
      title: '周',
      dataIndex: 'week',
      key: 'week',
      align: 'center',
      ellipsis: true,
    },
    {
      title: '年',
      dataIndex: 'year',
      key: 'year',
      align: 'center',
      ellipsis: true,
    }
  ];

  /**
   * 静态函数，根据新传入的props来映射到state。
   * 该函数必须有返回值。当props传入的内容不需要影响state，就必须返回一个null
   */
  static getDerivedStateFromProps(nextProps: ACrontabProps, prevState: ACrontabState) {
    console.info('index.getDerivedStateFromProps');
    // 重新查询清空表格勾选
    const { modalOpen, cronExpression } = nextProps;
    console.log(modalOpen, cronExpression);
    // 组件弹窗显示时才会处理
    if (modalOpen && cronExpression) {
      // 默认值，就不动
      if (cronExpression === '* * * * * ?') {
        return null;
      }
      let { second, minute, hour, day, month, week, year } = prevState;
      let tmpStateCronStr = second + " " + minute + " " + hour + " " + day + " " + month + " " + week;
      if (year) {
        tmpStateCronStr = tmpStateCronStr + " " + year;
      }
      // state的值不是默认的，按照state处理
      console.log(tmpStateCronStr);
      if (tmpStateCronStr !== '* * * * * ? *') {
        return prevState;
      }
      // state的值为默认的，按照props处理
      const cronArr = cronExpression.split(' ');
      console.info(cronArr);
      if (cronArr.length !== 6 && cronArr.length !== 7) {
        message.warning('输入的Cron表达式不合法，请重新配置');
        return null;
      }
      // 日和周只允许配置一个，要么配置日，要么配置周
      const dayFlag = cronArr[3] !== '?';
      const weekFlag = cronArr[5] !== '?';
      console.info(dayFlag, weekFlag);
      // 配置日，不配置周 dayFlag && !weekFlag
      // 不配置日，配置周 !dayFlag && weekFlag
      if (!((dayFlag && !weekFlag) || (!dayFlag && weekFlag))) {
        message.warning('输入的Cron表达式不合法，请重新配置');
        return null;
      }
      return {
        second: cronArr[0],
        minute: cronArr[1],
        hour: cronArr[2],
        day: cronArr[3],
        month: cronArr[4],
        week: cronArr[5],
        // 可以不指定年份
        year: cronArr[6] ? cronArr[6] : ''
      };
    }
    return null;
  }

  componentWillUnmount() {
    console.info('componentWillUnmount');
    // 组件销毁前的处理
    this.setState({
      second: '*',
      minute: '*',
      hour: '*',
      day: '*',
      month: '*',
      week: '?',
      year: '*'
    });
  }

  afterClose = () => {
    console.info('afterClose');
    this.setState({
      second: '*',
      minute: '*',
      hour: '*',
      day: '*',
      month: '*',
      week: '?',
      year: '*'
    });
  }

  onSecondChange = (second: string) => {
    this.setState({
      second
    });
    console.info(second);
  }

  onMinuteChange = (minute: string) => {
    this.setState({
      minute
    });
  }

  onHoueChange = (hour: string) => {
    this.setState({
      hour
    });
  }

  onDayChange = (day: string) => {
    this.setState({
      day
    });
  }

  onMonthChange = (month: string) => {
    this.setState({
      month
    });
  }

  onWeekChange = (week: string) => {
    this.setState({
      week
    });
  }

  onYearChange = (year: string) => {
    this.setState({
      year
    });
  }

  /**
   * 确定按钮点击事件，将各字段表达式传出去
   */
  onModalOk = () => {
    const { day, week } = this.state;
    // 日和周只允许配置一个，要么配置日，要么配置周
    const dayFlag = day !== '?';
    const weekFlag = week !== '?';
    console.info(dayFlag, weekFlag);
    // 配置日，不配置周 dayFlag && !weekFlag
    // 不配置日，配置周 !dayFlag && weekFlag
    if (!((dayFlag && !weekFlag) || (!dayFlag && weekFlag))) {
      message.error('不允许同时配置日规则和周规则');
      return;
    }
    const { onHandlerOK } = this.props;
    if (onHandlerOK) {
      const cronStr = this.generateCronExpression(this.state);
      onHandlerOK(cronStr);
    }
  }

  /**
   * 确定按钮点击事件，将各字段表达式传出去
   */
  onModalCancel = () => {
    const { onHandlerCancel } = this.props;
    if (onHandlerCancel) {
      onHandlerCancel();
    }
  }

  /**
   * 根据各组件拼接Cron表达式字符串
   * @returns Cron表达式字符串
   */
  generateCronExpression = (state: ACrontabState) => {
    const { second, minute, hour, day, month, week, year } = state;
    let tmpCronStr = second + " " + minute + " " + hour + " " + day + " " + month + " " + week;
    if (year) {
      tmpCronStr = tmpCronStr + " " + year;
    }
    return tmpCronStr;
  }

  render() {
    console.info('ACrontab.render');
    const { modalOpen } = this.props;
    const { second, minute, hour, day, month, week, year } = this.state;
    const getTabTitle = (text: string) => <div style={{ width: 50, textAlign: 'center' }}>{text}</div>;
    const tabPaneStyle = { paddingLeft: 10, marginTop: -10 };
    const cardBodyStyle = {
      backgroundColor: '#fff',
      borderRadius: '2px',
      outline: 'none',
      boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
      paddingLeft: '24px',
      paddingRight: '24px',
      paddingTop: '8px',
      paddingBottom: '8px'
    };
    const rowKey = (record: CrontabItem) => {
      const { second, minute, hour, day, month, week } = record;
      let tmpCronStr = second + " " + minute + " " + hour + " " + day + " " + month + " " + week;
      return tmpCronStr;
    };
    const cronStr = this.generateCronExpression(this.state);
    const dataSource: CrontabItem[] = [
      { second, minute, hour, day, month, week, year }
    ];
    // 根据 cronStr 计算最近5次运行时间
    const resultArr = cronExpressionChange(cronStr);
    console.info(resultArr);

    return (
      <Modal
        title='Cron时间表达式生成器'
        destroyOnClose
        open={modalOpen}
        maskClosable={false}
        width={1100}
        onOk={this.onModalOk}
        onCancel={this.onModalCancel}
        afterClose={this.afterClose}
        bodyStyle={{ paddingTop: '0px' }}
      >
        <ProCard
          bordered
          bodyStyle={cardBodyStyle}
        >
          <Tabs
            type='card'
            tabBarGutter={0}
          >
            <Tabs.TabPane tab={getTabTitle('秒')} key='second' style={tabPaneStyle}>
              <SecondPane value={second} onChange={this.onSecondChange}/>
            </Tabs.TabPane>
            <Tabs.TabPane tab={getTabTitle('分')} key='minute' style={tabPaneStyle}>
              <MinutePane value={minute} onChange={this.onMinuteChange}/>
            </Tabs.TabPane>
            <Tabs.TabPane tab={getTabTitle('时')} key='hour' style={tabPaneStyle}>
              <HourPane value={hour} onChange={this.onHoueChange}/>
            </Tabs.TabPane>
            <Tabs.TabPane tab={getTabTitle('日')} key='day' style={tabPaneStyle}>
              <DayPane value={day} onChange={this.onDayChange}/>
            </Tabs.TabPane>
            <Tabs.TabPane tab={getTabTitle('月')} key='month' style={tabPaneStyle}>
              <MonthPane value={month} onChange={this.onMonthChange}/>
            </Tabs.TabPane>
            <Tabs.TabPane tab={getTabTitle('周')} key='week' style={tabPaneStyle}>
              <WeekPane value={week} onChange={this.onWeekChange}/>
            </Tabs.TabPane>
            <Tabs.TabPane tab={getTabTitle('年')} key='year' style={tabPaneStyle}>
              <YearPane value={year} onChange={this.onYearChange}/>
            </Tabs.TabPane>
          </Tabs>
        </ProCard>
        <ProCard
          title='表达式字段'
          bordered
          bodyStyle={cardBodyStyle}
        >
          <Space direction='vertical' style={{ display: 'flex' }}>
            <Table<CrontabItem>
              columns={this.cronColumns}
              rowKey={rowKey}
              dataSource={dataSource}
              pagination={false}
              bordered
              size='small'
            />
            <Input value={cronStr} addonBefore='Cron时间表达式'/>
          </Space>
        </ProCard>
        <ProCard
          title='最近5次运行时间'
          bordered
          bodyStyle={cardBodyStyle}
        >
          <ul>
            {
              resultArr.map((item, index) => {
                return <li key={index}>{item}</li>
              })
            }
          </ul>
        </ProCard>
      </Modal>
    );
  }

}

export default ACrontab;